package atack.tesis.kelluntekun;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import org.vaadin.dialogs.ConfirmDialog;

import atack.tesis.kelluntekun.controllers.mainUserHandlerView;
import atack.tesis.kelluntekun.domain.Usuario;
import atack.tesis.kelluntekun.ui.componentes.SearchResultWindow;
import atack.tesis.kelluntekun.ui.componentes.UserFormView;
import atack.tesis.kelluntekun.ui.componentes.utils.UiUtils;
import atack.tesis.kelluntekun.utils.PasswordEncryptionService;

import com.vaadin.addon.jpacontainer.JPAContainer;
import com.vaadin.addon.jpacontainer.JPAContainerFactory;
import com.vaadin.data.Container.Filter;
import com.vaadin.data.util.filter.Compare;
import com.vaadin.data.validator.EmailValidator;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.PasswordField;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.themes.BaseTheme;
import com.vaadin.ui.themes.Reindeer;

public class LoginScreen extends GridLayout{
	private static final long serialVersionUID = 1L;
	
	private VerticalLayout vlyLogin;
//	private HorizontalLayout hlyRegister;
	
	private TextField tfUser;
	private PasswordField pfPassword;
	
	private Button btLogin;
	private Button btRegistrar;
	private Button btBusqueda;
	
	private UserFormView ufv;
	
	private JPAContainer<Usuario> usuario;
	
	public LoginScreen(){
		super(3,3);
		this.setMargin(true);
		this.setSpacing(false);
		this.setWidth("100%");
		this.setHeight("100%");
		this.setStyleName(Reindeer.LAYOUT_BLACK);
		
		//TODO 
		btBusqueda = new Button("Búsqueda");
		btBusqueda.setStyleName(BaseTheme.BUTTON_LINK);
		btBusqueda.setDescription("Acceder a la búsqueda de Snippets sin registrarse");
		btBusqueda.addListener(createBtBusquedaListener());
		addComponent(btBusqueda, 0, 0);
		setComponentAlignment(btBusqueda, Alignment.TOP_LEFT);
		
//		buildRegisterLayout();
		btRegistrar = new Button("Registrarse");
		btRegistrar.setStyleName(BaseTheme.BUTTON_LINK);
		btRegistrar.setDescription("Registrarse como un nuevo usuario");
		btRegistrar.addListener(createBtRegistrarListener());
		addComponent(btRegistrar, 2, 0);
		setComponentAlignment(btRegistrar, Alignment.TOP_RIGHT);
		
		
		Label lbIngreso =new Label("Kelluntekun App");
		lbIngreso.addStyleName(Reindeer.LABEL_H1);
		lbIngreso.setWidth(null);
		addComponent(lbIngreso,1,0);
		setComponentAlignment(lbIngreso, Alignment.TOP_CENTER);
		
		buildLoginFields();
		addComponent(vlyLogin,1,1);
		setComponentAlignment(vlyLogin, Alignment.MIDDLE_CENTER);
		
		tfUser.focus();
	}
	
	/**
	 * Construye los campos de email y password junto con el botón de login.
	 */
	private void buildLoginFields(){
		vlyLogin= new VerticalLayout();
		vlyLogin.setMargin(false);
		vlyLogin.setSpacing(false);
		vlyLogin.setWidth("150px");
		
		tfUser = new TextField("Mail:");
		tfUser.setWidth("150px");
		tfUser.setRequired(true);
		tfUser.setImmediate(true);
		tfUser.setInputPrompt("(ej. jhon@email.com)");
		tfUser.addValidator(new EmailValidator("El usuario debe ser un Email"));
		vlyLogin.addComponent(tfUser);
		
		pfPassword= new PasswordField("Contraseña:");
		pfPassword.setWidth("150px");
		pfPassword.setRequired(true);
		vlyLogin.addComponent(pfPassword);
		
		vlyLogin.addComponent(UiUtils.getLbSpace("120px", "10px"));
		
		btLogin = new Button("Ingresar");
		btLogin.setClickShortcut(KeyCode.ENTER);
		btLogin.setWidth("75px");
		btLogin.addListener(createBtLoginListener());
		
		vlyLogin.addComponent(btLogin);
		vlyLogin.setComponentAlignment(btLogin, Alignment.BOTTOM_RIGHT);
	}
	
	/**
	 * construye el listener para el evento de logueo.
	 * @return ClickListener 
	 */
	private Button.ClickListener createBtLoginListener(){
		
		return new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				if(tfUser.isValid()&&!pfPassword.getValue().toString().equals("")){
					
					if(auntenticarUsuario(tfUser.getValue().toString(),pfPassword.getValue().toString())){
						System.out.println("#########################################################>" +
								""+usuario.getItem(usuario.firstItemId()).getEntity().getNick());
						KelluntekunApplication.getInstance().setUser(usuario.getItem(usuario.firstItemId()).getEntity());
						
						KelluntekunApplication.getInstance().getMainWindow().setContent(new mainUserHandlerView());
					}
					else{
						getWindow().showNotification(UiUtils.getWarningNotification(
								"El nombre de usuario o la contraseña introducidos no son correctos", ""));
						clearLoginFields();
					}
				}
				else{
					getWindow().showNotification(UiUtils.getWarningNotification("Debe llenar los campos correctamente",
							"<center>(Usuario y Contraseña)</center>"));
					clearLoginFields();
				}
			}
		};
	}
	
	private Button.ClickListener createBtRegistrarListener(){
		return new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				ufv= new UserFormView();
				addListenersUserFormView();
				getWindow().addWindow(ufv);
			}
		};
	}
	
	private Button.ClickListener createBtBusquedaListener(){
		return new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				SearchResultWindow srw = new SearchResultWindow();
				getWindow().addWindow(srw);
			}
		};
	}
	
	/**
	 * Limpia los campos del login de usuario.
	 */
	private void clearLoginFields(){
//		tfUser.setValue("");
		pfPassword.setValue("");
	}
	
	/**
	 * Realiza la verificación de la validez de los datos de autenticación introducidos para loguearse en la aplicación.
	 * @param user
	 * @param password
	 * 
	 * @return true si el user y password se correponden con la BD, false de lo contrario
	 */
	private Boolean auntenticarUsuario(String user, String password){
		usuario = JPAContainerFactory.make(Usuario.class,KelluntekunApplication.PERSISTENCE_UNIT);
		
		Filter filtroMail= new Compare.Equal("mail", user);
		usuario.addContainerFilter(filtroMail);
		
		if (usuario.size()==1){
			try {
				return(PasswordEncryptionService.authenticate(password, 
						PasswordEncryptionService.toByteArray(usuario.getItem(usuario.firstItemId()).getEntity().getPassword()), 
						PasswordEncryptionService.toByteArray(usuario.getItem(usuario.firstItemId()).getEntity().getSalt())));
			} catch (NoSuchAlgorithmException e) {
				//  Auto-generated catch block
				e.printStackTrace();
				return false;
			} catch (InvalidKeySpecException e) {
				//  Auto-generated catch block
				e.printStackTrace();
				return false;
			}
			
		}
		else{
			return false;
		}
//		Filter filtroPassword= new Compare.Equal("password", password);
//		usuario.addContainerFilter(filtroPassword);
	}
	
	/**
	 * Agrega los listeners a los botones del formulario de registro de usuarios.
	 */
	private void addListenersUserFormView(){
		
		ufv.getBtCancelar().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				
				ConfirmDialog.show(getWindow(), "Cancelar", "¿Estas seguro de querer cancelar?, se perderan los datos.", "Ok", "Volver",
						new ConfirmDialog.Listener(){
							private static final long serialVersionUID = 1L;
							public void onClose(ConfirmDialog dialog){
								if (dialog.isConfirmed()){
									//TODO confirm dialog.
									getWindow().removeWindow(ufv);
								}
							}
						});
				
			}
		});
		
		ufv.getBtEnviar().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				if (ufv.isValid()){
					if(!verificarDuplicidadMail(ufv.getUsuario())){
						//si el mail no esta en la BD se crea usaruio.
							agregarNuevoUsuario(ufv.getUsuario());
							getWindow().removeWindow(ufv);
						
					}
					else {
						getWindow().showNotification(UiUtils.getWarningNotification("Ya existe un usuario asociado al Email ingresado",
								"<center>Puedes intentar loguearte o registrarte con otro Email.</center>"));
						tfUser.focus();
					}
				}
				else{
					//notificacion para rellenar bien los campos.
					getWindow().showNotification("Debes llenar los campos correctamente"
							,Notification.TYPE_WARNING_MESSAGE);
				}
			}
		});
		
	}
	
	/**
	 * Verifica si el mail asociado al usuario que se desea crear ya existe en la BD
	 * @param user
	 * @return Retorna true si es que el mail ya existe en la BD
	 */
	private Boolean verificarDuplicidadMail(Usuario user){
		usuario = JPAContainerFactory.make(Usuario.class,KelluntekunApplication.PERSISTENCE_UNIT);
		Filter filtroMail= new Compare.Equal("mail", user.getMail());
		usuario.addContainerFilter(filtroMail);
		if (usuario.size()==0){
			return false;
		}
		else{
			return true;
		}
	}
	
	/**
	 * Agrega un nuevo usuario a la Base de Datos.
	 * @param newUser
	 * 			El nuevo usuario
	 */
	private void agregarNuevoUsuario(Usuario newUser){
		//Encriptar password.
		byte[] salt;
		byte[] passEncriptada;
		try {
			salt = PasswordEncryptionService.generateSalt();
			passEncriptada = PasswordEncryptionService.getEncryptedPassword(newUser.getPassword(), salt);
			
			newUser.setSalt(PasswordEncryptionService.toHexString(salt));
			newUser.setPassword(PasswordEncryptionService.toHexString(passEncriptada));
			
			usuario = JPAContainerFactory.make(Usuario.class,KelluntekunApplication.PERSISTENCE_UNIT);
			usuario.addEntity(newUser);
			
			getWindow().showNotification("Tu Usuario ha sido creado correctamente<br>",
					"<br><center>Puedes intentar loguearte</center>"
					,Notification.TYPE_TRAY_NOTIFICATION,true);
			
		} catch (NoSuchAlgorithmException e) {
			//  Auto-generated catch block
			//notificacion Error.
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			//  Auto-generated catch block
			e.printStackTrace();
		}
	}
	
//	private void buildRegisterLayout() {
//		hlyRegister = new HorizontalLayout();
//		hlyRegister.setWidth(null);
//		hlyRegister.setHeight(null);
//		hlyRegister.setSpacing(false);
//		hlyRegister.setMargin(false);
//		
//		hlyRegister.addComponent(UiUtils.getLbSpace("15px", "5px"));
//	}
}
